﻿using System;
using System.Net;
using System.Net.Http;
using Best.SmartCms.Core.Utility;
using Best.SmartCms.Utility.Common;
using Best.SmartCms.Utility.Entities.Weixin;
using Newtonsoft.Json;

namespace Best.SmartCms.Utility
{
    /// <summary>
    /// 应用授权作用域
    /// </summary>
    public enum OAuthScope
    {
        /// <summary>
        /// 不弹出授权页面，直接跳转，只能获取用户openid
        /// </summary>
        snsapi_base,
        /// <summary>
        /// 弹出授权页面，可通过openid拿到昵称、性别、所在地。并且，即使在未关注的情况下，只要用户授权，也能获取其信息
        /// </summary>
        snsapi_userinfo
    }
    /// <summary>
    /// 微信小程序Api调用
    /// </summary>
    public class WeixinApiHelper
    {

        /// <summary>
        /// 获取AccessToken（OAuth专用）
        /// </summary>
        /// <param name="appId">公众号的唯一标识</param>
        /// <param name="secret">公众号的appsecret</param>
        /// <param name="code">code作为换取access_token的票据，每次用户授权带上的code将不一样，code只能使用一次，5分钟未被使用自动过期。</param>
        /// <param name="grantType">填写为authorization_code（请保持默认参数）</param>
        /// <returns></returns>
        public static OAuthAccessTokenResult GetAccessToken(string appId, string secret, string code, string grantType = "authorization_code")
        {
            var url =$"https://api.weixin.qq.com/sns/oauth2/access_token?appid={appId.AsUrlData()}&secret={secret.AsUrlData()}&code={code.AsUrlData()}&grant_type={grantType.AsUrlData()}";
            using (var client = new HttpClient())
            {
                var response = client.GetAsync(url).Result;
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    var result = response.Content.ReadAsStringAsync().Result;
                    var data = JsonConvert.DeserializeObject<OAuthAccessTokenResult>(result);
                    return data;
                }

                return null;
            }
        }


        /// <summary>
        /// 获取验证地址
        /// </summary>
        /// <param name="appId">公众号的唯一标识</param>
        /// <param name="redirectUrl">授权后重定向的回调链接地址，请使用urlencode对链接进行处理</param>
        /// <param name="state">重定向后会带上state参数，开发者可以填写a-zA-Z0-9的参数值，最多128字节</param>
        /// <param name="scope">应用授权作用域，snsapi_base （不弹出授权页面，直接跳转，只能获取用户openid），snsapi_userinfo （弹出授权页面，可通过openid拿到昵称、性别、所在地。并且，即使在未关注的情况下，只要用户授权，也能获取其信息）</param>
        /// <param name="responseType">返回类型，请填写code（或保留默认）</param>
        /// <param name="addConnectRedirect">加上后可以解决40029-invalid code的问题（测试中）</param>
        /// <returns></returns>
        public static string GetAuthorizeUrl(string appId, string redirectUrl, string state, OAuthScope scope, string responseType = "code", bool addConnectRedirect = true)
        {
            //var url =string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type={2}&scope={3}&state={4}{5}#wechat_redirect",
            //        appId.AsUrlData(), redirectUrl.AsUrlData(), responseType.AsUrlData(), scope.ToString("g").AsUrlData(), state.AsUrlData(),
            //        addConnectRedirect ? "&connect_redirect=1" : "");

            var url =
                string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type={2}&scope={3}&state={4}#wechat_redirect",
                    appId, System.Web.HttpUtility.UrlEncode(redirectUrl), responseType, scope, state);

            return url;
        }

        /// <summary>
        /// code 换取 session_key
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="secret"></param>
        /// <param name="jsCode"></param>
        /// <param name="grantType">保持默认：authorization_code</param>
        /// <returns></returns>
        public static JsCodeSessionJsonResult JsCode2WxSession(string appId, string secret, string jsCode, string grantType = "authorization_code")
        {
            string urlFormat = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type={3}";
            var url = string.Format(urlFormat, appId, secret, jsCode, grantType);
            using (var client = new HttpClient())
            {
                var response = client.GetAsync(url).Result;
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    var result = response.Content.ReadAsStringAsync().Result;
                    var data = JsonConvert.DeserializeObject<JsCodeSessionJsonResult>(result);
                    return data;
                }

                return null;
            }
        }

        /// <summary>
        /// 获取凭证接口
        /// </summary>
        /// <param name="grantType">获取access_token填写client_credential</param>
        /// <param name="appid">第三方用户唯一凭证</param>
        /// <param name="secret">第三方用户唯一凭证密钥，既appsecret</param>
        /// <returns></returns>
        public static AccessTokenResult GetToken(string appid, string secret, string grantType = "client_credential")
        {
            var url = $"https://api.weixin.qq.com/cgi-bin/token?grant_type={grantType.AsUrlData()}&appid={appid.AsUrlData()}&secret={secret.AsUrlData()}";
            using (var client = new HttpClient())
            {
                var response = client.GetAsync(url).Result;
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    var result = response.Content.ReadAsStringAsync().Result;
                    NLogManager.LogTrace($"获取WeixinToken：当前时间{DateTime.Now},{result}");
                    var data = JsonConvert.DeserializeObject<AccessTokenResult>(result);
                    return data;
                }

                return null;
            }
        }

        private static readonly object ObjectToken = new object();

        /// <summary>
        /// 获取可用AccessTokenResult对象
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="appSecret"></param>
        /// <param name="getNewToken">是否强制重新获取新的Token</param>
        /// <returns></returns>
        public static AccessTokenResult GetAccessTokenResult(string appId, string appSecret, bool getNewToken = false)
        {
            //var tokenKey = "Wx_" + appId;
            //var accessToken = RedisService.GetRedisValue<AccessTokenExpireInfo>(tokenKey);
            //if (getNewToken || accessToken == null || accessToken.AccessTokenExpireTime <= DateTime.Now)
            //{
            //    lock (ObjectToken)
            //    {
            //        accessToken = new AccessTokenExpireInfo { AccessTokenResult = GetToken(appId, appSecret) };
            //        //已过期，重新获取
            //        accessToken.AccessTokenExpireTime = TimeHelper.GetExpireTime(accessToken.AccessTokenResult.expires_in);
            //        RedisService.SetRedisObject(tokenKey, accessToken, TimeSpan.FromSeconds(7200)); //更新到缓存
            //    }
            //}

            //return accessToken.AccessTokenResult;

            return null;
        }

        /// <summary>
        /// 微信小程序发送模版消息
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="msgData"></param>
        /// <returns></returns>

        public static WxJsonResult SendTemplateMessage(string accessToken, TemplateMessage msgData)
        {
            string url = $"https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token={accessToken}";
            var jsonData = JsonConvert.SerializeObject(msgData);
            StringContent content = new StringContent(jsonData);
            using (var client = new HttpClient())
            {
                var response = client.PostAsync(url, content).Result;
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    var result = response.Content.ReadAsStringAsync().Result;
                    var data = JsonConvert.DeserializeObject<WxJsonResult>(result);
                    return data;
                }

                return null;
            }
        }


        /// <summary>
        /// 微信公众号发送模版消息
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="msgData"></param>
        /// <returns></returns>

        public static WxJsonResult SendTemplateMessage(string accessToken, TempleteModel msgData)
        {
            string url = $"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={accessToken}";
            var jsonData = JsonConvert.SerializeObject(msgData);
            StringContent content = new StringContent(jsonData);
            using (var client = new HttpClient())
            {
                var response = client.PostAsync(url, content).Result;
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    var result = response.Content.ReadAsStringAsync().Result;
                    var data = JsonConvert.DeserializeObject<WxJsonResult>(result);
                    return data;
                }

                return null;
            }
        }

        /// <summary>
        /// 微信公众号发送模版消息
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="appSecret"></param>
        /// <param name="msgData"></param>
        /// <returns></returns>
        public static WxJsonResult SendTemplateMessage(string appId, string appSecret, TempleteModel msgData)
        {
            var accessTokenResult = GetAccessTokenResult(appId, appSecret);
            var accessToken = "";
            if (accessTokenResult.errcode == 0)
            {
                accessToken = accessTokenResult.access_token;
            }

            if (string.IsNullOrWhiteSpace(accessToken))
            {
                return null;
            }

            return SendTemplateMessage(accessToken, msgData);
        }

        /// <summary>
        /// 微信小程序发送模版消息
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="appSecret"></param>
        /// <param name="msgData"></param>
        /// <returns></returns>
        public static WxJsonResult SendTemplateMessage(string appId, string appSecret, TemplateMessage msgData)
        {
            var accessTokenResult = GetAccessTokenResult(appId, appSecret);
            var accessToken = "";
            if (accessTokenResult.errcode == 0)
            {
                accessToken = accessTokenResult.access_token;
            }

            if (string.IsNullOrWhiteSpace(accessToken))
            {
                return null;
            }

            return SendTemplateMessage(accessToken, msgData);
        }

        /// <summary>
        /// 发送文本信息
        /// </summary>
        /// <param name="appId">AccessToken或AppId（推荐使用AppId，需要先注册）</param>
        /// <param name="appSecret"></param>
        /// <param name="openId"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public static WxJsonResult SendText(string appId, string appSecret, string openId, string content)
        {
            var msgData = new
            {
                touser = openId,
                msgtype = "text",
                text = new
                {
                    content = content
                }
            };

            var accessTokenResult = GetAccessTokenResult(appId, appSecret);
            var accessToken = "";
            if (accessTokenResult.errcode == 0)
            {
                accessToken = accessTokenResult.access_token;
            }

            if (string.IsNullOrWhiteSpace(accessToken))
            {
                return null;
            }

            string url = $"https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={accessToken}";
            var jsonData = JsonConvert.SerializeObject(msgData);
            StringContent stringContent = new StringContent(jsonData);
            using (var client = new HttpClient())
            {
                var response = client.PostAsync(url, stringContent).Result;
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    var result = response.Content.ReadAsStringAsync().Result;
                    var data = JsonConvert.DeserializeObject<WxJsonResult>(result);
                    return data;
                }

                return null;
            }
        }
    }
}